#include "StdAfx.h"
#include "RscIirFsm.h"

CRscIirFsm::CRscIirFsm(uint32_t g1, uint32_t g2)
{
	mG1 = invert_bits(g1);
	mG2 = invert_bits(g2);
	uint32_t G1order, G2order;

	G1order = log((float)g1) / log(2.);
	if((1<<G1order) < g1){
		G1order++;
	}
	if(G1order>0){
		G1order--;
	}else{
		G1order=1;
	}

	G2order = log((float)g2) / log(2.);
	if((1<<G2order) < g2){
		G2order++;
	}
	if(G2order>0){
 		G2order--;
	}else{
		G2order=1;
	}


	mOrder = (G1order > G2order) ? G1order : G2order;

	mStateMask = (uint32_t)(1<<mOrder)-1;

	mToState = new uint32_t*[2];  //mToState[x][y] = state that machine will be if input is x and current state is y;
	mFromState = new uint32_t*[2]; //mFromState[x][y] = state that machine was if input was x and current state is y;
	mOutput = new bool*[2]; //mOutput[x][y] output bit if machine is in state y and input is x
	for(uint32_t i=0;i<2;i++){
		mToState[i] = new uint32_t[1<<mOrder];
		mFromState[i] = new uint32_t[1<<mOrder];
		mOutput[i] = new bool[1<<mOrder];
	}
    for(uint32_t i=0;i<2;i++){
        for(uint32_t j=0;j<1<<mOrder;j++){
            mToState[i][j] = 0xFFFFFFFF;
            mFromState[i][j] = 0xFFFFFFFF;
            mOutput[i][j] = 0xFFFFFFFF;
        }
    }

	
    
    CreateStateTransitions();
};

bool
CRscIirFsm::Encode(CMessage *message, CMessage *parity, bool terminate)
{  
    bool* msg = message->GetBoolMessage();
    bool* par = new bool[message->GetSize()];
	uint32_t actual_state = 0;	
	uint32_t encode_size = message->GetSize()-1;
	if(terminate){
		encode_size-=mOrder;	
	}
	uint32_t i;

    for(i=0;i<encode_size;i++){    
		uint32_t ind = msg[i] ? 1 : 0;
		par[i] = mOutput[ind][actual_state];
		actual_state = mToState[ind][actual_state];
    }  
	
	//termination loop (if any)
	for(;i<message->GetSize()-1;i++){    
		if(mToState[0][actual_state]&0x1){
			msg[i]=true;
		}else{
			msg[i]=false;
		}
		uint32_t ind = msg[i] ? 1 : 0;
		par[i] = mOutput[ind][actual_state];
		actual_state = mToState[ind][actual_state];
    }  

    if(terminate){
        message->UpdateDoubleMessage();
    }

    parity->Replace(par,message->GetSize());
	parity->UpdateDoubleMessage();
    delete par;
    return true;
}

bool
CRscIirFsm::CreateStateTransitions()
{		
    
		for(uint32_t input=0;input<2;input++){
			for(uint32_t state=0;state<(1<<mOrder);state++){        
				uint32_t bits = (state << 1) | input;			
				bool g10xorIn = vector_xor(bits & mG1);
				uint32_t new_state = (state << 1) | (g10xorIn ? 0x1 : 0x0);
				mOutput[input][state] = vector_xor(new_state & mG2);
				new_state &= mStateMask;
				mToState[input][state] = new_state;
				mFromState[input][new_state] = state;				
			}       
		}  
	return true;
};
